Infinite Square Well
슈뢰딩거 방정식을 무한 사각형 우물 형태의 퍼텐셜에서 푸는 것은 양자역학에서 가장 기본적인 예제 중 하나입니다.
구체적으로 퍼텐셜을 다음과 같습니다:
$$
V(x) = \begin{cases}
0 & (0 \le x \le a), \\
\infty & \text{otherwise.}
\end{cases}
$$
위의 퍼텐셜에 대해 시간에 무관한 슈뢰딩거 방정식
$$
- \frac{\hbar^2}{2m}\frac{d^2\psi}{dx^2} + V\psi = E\psi
$$
을 풀어 정상상태의 파동함수를 얻을 수 있습니다:
$$
\psi_n(x) = \sqrt{\frac{2}{a}}\sin\left(\frac{n\pi x}{a}\right).
$$
또한 이들의 선형결합으로부터 시간을 포함하는 일반적인 해를 얻을 수 있습니다:
$$
\Psi(x,t) = \sum_{n=1}^{\infty}c_n \sqrt{\frac{2}{a}}\sin \left(\frac{n\pi x}{a}\right)e^{-iE_nt/\hbar}.\tag{1}
$$
여기서 $E_n = \frac{n^2\pi^2\hbar^2}{2ma^2}$이며 $c_n$은 $t=0$일 때의 파동함수로부터 구할 수 있습니다:
$$
c_n = \sqrt{\frac{2}{a}} \int_0^a \sin\left(\frac{n\pi x}{a}\right)\Psi(x, 0)dx.
$$
여기서는 초기 파동함수 $\Psi(x, 0)$을 시간에 의존하는 슈뢰딩거 방정식
$$
i\hbar \frac{\partial\Psi}{\partial t} = - \frac{\hbar^2}{2m}\frac{\partial^2\Psi}{\partial x^2}+V\Psi
$$
을 이용하여 시간에 대한 파동함수 $\Psi(x, t)$를 수치적으로 구해볼 것입니다.
Exact Solution
우리는 이미 식 (1)과 같은 정확한 해를 알고 있습니다.
이를 통해 $\Psi(x, 0)$이 $\psi_{n_1}(x)$와 $\psi_{n_2}(x)$의 선형결합으로 표현될 때, $\Psi(x, T)$를 구할 수 있습니다.
다음 코드는 그러한 $\Psi(x, 0)$와 $\Psi(x, T)$를 구하는 과정입니다.
import matplotlib.pyplot as plt
import numpy as np
a = 1
N = 100
hbar = 1
m = 1
kappa = 1j * hbar / 2 / m
dt = 0.0001
tN = 1000
T = dt * tN
x = np.linspace(0, a, N + 1)
dx = a / N
n1 = 1
n2 = 2
Psi = 1 / np.sqrt(2) * (np.sqrt(2 / a) * np.sin(n1 * np.pi / a * x)
+ np.sqrt(2 / a) * np.sin(n2 * np.pi / a * x))
Psi = np.array(Psi, dtype=np.complex128)
E_1 = n1 * n1 * np.pi * np.pi * hbar * hbar / 2 / m / a / a
E_2 = n2 * n2 * np.pi * np.pi * hbar * hbar / 2 / m / a / a
Psi_sol = 1 / np.sqrt(2) * (np.sqrt(2 / a) * np.sin(n1 * np.pi / a * x) * np.exp(-1j * E_1 * T / hbar)
+ np.sqrt(2 / a) * np.sin(n2 * np.pi / a * x) * np.exp(-1j * E_2 * T / hbar))
plt.plot(x, np.abs(Psi) ** 2)
다음 그림은 $n_1=1$, $n_2=2$, $a=1$일 때 $|\Psi(x, 0)|^2$을 나타냅니다.
Time evolution
유한 차분법을 사용하여 $\Psi$를 시간에 따라 적분할 것입니다.
가장 단순한 방법은 전방-시간 중심-공간forward-time centered-space(FTCS) 방법입니다.
이는 공간에 대해선 중심 차분을 사용하고
$$
\frac{\partial^2\Psi_i}{\partial x^2} \to \frac{\Psi(x_{i+1}) - 2 \Psi(x_{i}) + \Psi(x_{i-1})}{(\Delta x)^2} + \mathcal{O}(\Delta x^2),
$$
시간에 대해선 전방 차분을 사용합니다:
$$
\frac{\partial \Psi_i}{\partial t} \to \frac{\Psi_i^{n+1} - \Psi_i^{n}}{\Delta t} + \mathcal{O}(\Delta t).
$$
이는 단순하지만 안정적인 적분을 위해 $\Delta x^2$에 비례하는 매우 작은 $\Delta t$를 선택해야 한다는 문제가 있습니다.
여기서는 암묵적 차분 방법implicit differencing scheme을 사용하겠습니다.
이는
$$
\frac{\partial \Psi}{\partial t} = \kappa \frac{\partial^2 \Psi}{\partial x^2}
$$
형태의 방정식을
$$
\Psi_i^{n+1} = \Psi_i^n + \frac{\kappa \Delta t}{\Delta x^2}(\Psi^{n+1}_{i + 1} - 2\Psi^{n+1}_{i} + \Psi^{n+1}_{i - 1})
$$
으로 적분합니다.
우변에 $n+1$에 대한 정보가 있기 때문에 특정한 $\Psi^n_i$에 대해 다음 단계의 $\Psi^{n+1}_i$를 곧바로 계산할 수 없습니다.
대신 위의 식을 다음과 같이 변형할 수 있습니다:
$$
\left(1 + \frac{2\kappa \Delta t}{\Delta x^2}\right)\Psi^{n+1}_i - \frac{\kappa \Delta t}{\Delta x^2}(\Psi^{n+1}_{i+1} + \Psi^{n+1}_{i-1}) = \Psi^n_i.
$$
모든 $1 \le i \le N - 1$에 대해 위의 식을 쓸 수 있고, $i=0$, $i=N$의 경우 $\Psi^{n+1}_i = \Psi^n_i$의 경계조건을 적용하겠습니다.
이제 연립방정식을 $\bm{A}\Psi^{n+1}=\Psi^n$으로 나타낼 수 있습니다. 여기서 $\bm{A}$는 다음과 같은 $(N+1)\times (N+1)$ 행렬입니다:
$$
\bm{A}=\begin{pmatrix}
1 & 0 & 0 & 0 & 0\\
- \frac{\kappa \Delta t}{\Delta x^2} & 1 + \frac{2\kappa \Delta t}{\Delta x^2} & - \frac{\kappa \Delta t}{\Delta x^2} & 0 & 0\\
0 & - \frac{\kappa \Delta t}{\Delta x^2} & 1 + \frac{2\kappa \Delta t}{\Delta x^2} & - \frac{\kappa \Delta t}{\Delta x^2} & 0 \\
& \ddots & \ddots & \ddots & \\
0 & 0 & - \frac{\kappa \Delta t}{\Delta x^2} & 1 + \frac{2\kappa \Delta t}{\Delta x^2} & - \frac{\kappa \Delta t}{\Delta x^2} \\
0 & 0 & 0 & 0 & 1
\end{pmatrix}.
$$
따라서 각 시간 단계마다 위의 행렬 방정식을 풀어 새로운 $\Psi$를 얻는 과정을 반복합니다.
for time_step in range(tN):
A = np.zeros((N + 1, N + 1), dtype=np.complex128)
A[0][0] = A[N][N] = 1
for i in range(1, N):
A[i][i] = 1 + 2 * kappa * dt / dx / dx
A[i][i + 1] = A[i][i - 1] = - kappa * dt / dx / dx
Psi = np.linalg.solve(A, Psi)
$\bm{A}$가 삼대각 행렬tridiagonal matrix임을 이용하면 더 빠르게 풀 수 있습니다.
여기서는 scipy의 solve_banded
를 이용하였습니다.
from scipy.linalg import solve_banded
for time_step in range(tN):
A_band = np.zeros((3, N + 1), dtype=np.complex128)
A_band[1][0] = A_band[1][N] = 1
A_band[1][1:N] = 1 + 2 * kappa * dt / dx / dx
A_band[0][2:] = - kappa * dt / dx / dx
A_band[2][:N - 1] = - kappa * dt / dx / dx
Psi = solve_banded((1, 1), A_band, Psi)
이제 수치적으로 얻은 해와 해석적 해를 비교해보겠습니다.
plt.plot(x, np.abs(Psi) ** 2, label='numerical')
plt.plot(x, np.abs(Psi_sol) ** 2, label='exact')
다음 그림은 시간 간격 $\Delta t = 0.0001$로 $1000$번 적분하여 얻은 $|\Psi(x, 0.1)|^2$을 나타낸 것입니다.
해석적 해와 크게 차이를 보이지 않지만 시간 간격 또는 전체 시간을 증가시키면 더 큰 오차를 볼 수 있습니다.
plt.plot(x, Psi.real, label='num_real')
plt.plot(x, Psi.imag, label='num_imag')
plt.plot(x, Psi_sol.real, label='exact_real')
plt.plot(x, Psi_sol.imag, label='exact_imag')
다음 그림은 위와 같은 과정으로 얻은 $\Psi(x, 0.1)$을 실수부와 허수부로 나누어 나타낸 것입니다.
다음 영상은 $n_1 = 1$, $n_2=2$일 때의 결과입니다.
다음 영상은 $n_1 = 2$, $n_2=3$일 때의 결과입니다.
다음 영상은 $n_1 = 3$, $n_2=7$일 때의 결과입니다.
Using Runge-Kutta Method
$4$차 정확도를 가지는 Runge-Kutta 방법을 사용하면 더 나은 결과를 얻을 수도 있습니다.
다음 영상은 위와 같이 $(n_1, n_2) = (2, 3), (3, 7)$일 때 4차 Runge-Kutta 방법을 사용한 결과입니다.
다음 영상은 $n_1 = 3$, $n_2=7$일 때의 결과입니다.
Copyright 2023ⓒ D.C. Kim. All Rights Reserved.